/*
 *  AStream.cpp
 *  libavid
 *
 *  Created by Peter on 23.02.12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */

#include "AStream.h"

AStream::AStream( const std::string& fileName )
{
	// TODO: Handle in/out/io
	_stream.open( fileName.c_str(), std::ios::in | std::ios::binary );
	
	if( _stream.fail() )
		throw "Failed to open file.";
}

AStream::~AStream()
{
	_stream.close();
}

void AStream::setSwapBytes( bool value )
{
	_swapBytes = value;
}

void AStream::swapBytes( UInt16& val )
{
	// TODO: Test
	val = ( ( val & 0x00ff ) << 8 ) | ( val >> 8 );
}

void AStream::swapBytes( Int16& val )
{
	// TODO: Test
	val = ( ( val & 0x00ff ) << 8 ) | ( val >> 8 );	
}

void AStream::swapBytes( UInt32& val )
{
	// TODO: Implement
	TR_NOT_IMPLEMENTED();
}

void AStream::swapBytes( Int32& val )
{
	// TODO: Implement
	TR_NOT_IMPLEMENTED();
}

void AStream::swapBytes( Int64& val )
{
	// TODO: Implement
	TR_NOT_IMPLEMENTED();
}

UInt8 AStream::peek()
{
	return _stream.peek();
}

void AStream::swapBytes( Float64& val )
{
	// This is off the internet, seems correct to me, though.
	// NEEDS TESTING!!!
	unsigned char* cptr = (unsigned char *)&val;
	unsigned char tmp;
	
	tmp = cptr[0];
	cptr[0] = cptr[7];
	cptr[7] = tmp;
	tmp = cptr[1];
	cptr[1] = cptr[6];
	cptr[6] = tmp;
	tmp = cptr[2];
	cptr[2] = cptr[5];
	cptr[5] =tmp;
	tmp = cptr[3];
	cptr[3] = cptr[4];
	cptr[4] = tmp;
	
}

std::string AStream::readString()
{
	Int16 len;
	std::string str;

	// Read the 16-bit length field
	readPod( len );
	
	// Sometimes a length of -1 is used for "not set"
	if( len == 0 || len == -1 )
		return "";
	
	// Avoid reading strings with negative lengths for obvious reasons
	TR_ASSERT( len > 0 );
	
	str.resize( len );
	
	// WARNING: Implementation dependent, we should probably do this differently
	_stream.read( &str[ 0 ], len );
	
	return str;
}

void AStream::writeString( const std::string& str )
{
	// We write strings as a 16-bit length field, followed
	// by the string data without a trailing zero.
	
	Int16 len = str.length();
	
	if( _swapBytes )
		swapBytes( len );
	
	writePod( len );
	
	_stream.write( str.c_str(), str.length() );
}

std::streampos AStream::getPos() const
{
	return const_cast< std::fstream& >( _stream ).tellg();
}

void AStream::skip( int numBytes )
{
	TR_CHECK( numBytes >= 0 );
	_stream.seekg( numBytes, std::ios::cur );
}

void AStream::seekRelative( int numBytes )
{
	_stream.seekg( numBytes, std::ios::cur );
}

bool AStream::readBool()
{
	UInt8 val;
	readPod( val );
	
	return static_cast< bool >( val );
}

void AStream::readBuffer( void* buffer, std::size_t size )
{
	_stream.read( reinterpret_cast< char* >( buffer ), size  );
}